#
# Copyright (c) 2006 Martin Decky
# Copyright (c) 2006 Jakub Jermar
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
#
# - Redistributions of source code must retain the above copyright
#   notice, this list of conditions and the following disclaimer.
# - Redistributions in binary form must reproduce the above copyright
#   notice, this list of conditions and the following disclaimer in the
#   documentation and/or other materials provided with the distribution.
# - The name of the author may not be used to endorse or promote products
#   derived from this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#

/*
 * start.S
 *
 * Start code for Sparc64 RTEMS
 *
 * This is based on the boot.S file of the HelenOS sparc64 architecture.
 * http://www.helenos.org/
 * ${helenos}/boot/arch/sparc64/loader/boot.S
 *
 * Modifications for the RTEMS executive are 
 *   COPYRIGHT (c) 2010 Gedare Bloom.
 *   COPYRIGHT (c) 2010 Eugen Leontie.
 *
 * $Id: start.S,v 1.2 2011/10/06 16:46:36 joel Exp $
 */

#include <rtems/asm.h>
#include <rtems/score/cpu.h>

#include <arch/boot.h>
#include <arch/stack.h>

#include <arch/mm/mmu.h>
#include <arch/mm/tlb.h>
#include <arch/mm/tte.h>

#define PHYSMEM_ADDR_SIZE 43


#define SET_TLB_TAG(VA, r1, context) \
	set VA | (context << TLB_TAG_ACCESS_CONTEXT_SHIFT), %r1

#define TTE_LOW_DATA(imm) 	(TTE_CP | TTE_P | LMA | (imm))

#define SET_TLB_DATA(r1, r2, imm) \
	set TTE_LOW_DATA(imm), %r1; \
	or %r1, %l5, %r1; \
	mov PAGESIZE_512K, %r2; \
	sllx %r2, TTE_SIZE_SHIFT, %r2; \
	or %r1, %r2, %r1; \
	mov 1, %r2; \
	sllx %r2, TTE_V_SHIFT, %r2; \
	or %r1, %r2, %r1;

#define SET_TLB_DEMAP_CMD(r1, context_id) \
  set (TLB_DEMAP_CONTEXT << TLB_DEMAP_TYPE_SHIFT) | (context_id << \
    TLB_DEMAP_CONTEXT_SHIFT), %r1

#define PSTATE_PRIV_BIT	4

.register %g2, #scratch
.register %g3, #scratch
.register %g6, #scratch
.register %g7, #scratch

.section BOOTSTRAP, "ax"

PUBLIC(_start)
  .global _start
  SYM(_start):
    start:
    b 1f
    nop

    /*
     * This header forces SILO to load the image at 0x4000.
     * More precisely, SILO will think this is an old version of Linux.
     */
    .ascii "HdrS"
    .word 0
    .half 0
    .half 0
    .half 0
    .half 0
    .global silo_ramdisk_image
    silo_ramdisk_image:
    .word 0
    .global silo_ramdisk_size
    silo_ramdisk_size:
    .word 0

    .align 8
    1:	
    /*
     * Disable interrupts and disable address masking.
     */
    wrpr %g0, PSTATE_PRIV_BIT, %pstate

    wrpr %g0, SPARC_NUMBER_OF_REGISTER_WINDOWS - 2, %cansave	! set maximum saveable windows
    wrpr %g0, 0, %canrestore		! get rid of windows we will never need again
    wrpr %g0, 0, %otherwin			! make sure the window state is consistent
    wrpr %g0, SPARC_NUMBER_OF_REGISTER_WINDOWS - 1, %cleanwin	! prevent needless clean_window traps for kernel

  /* g4 needs to be cleared for gcc */
  mov %g0, %g4

  /* Install stack */
setstack:
	set SYM(StackStart), %sp
	add %sp, -STACK_BIAS, %sp

takemmu:
  /* BSP-specific pre-bootcard initializations */
!  call SYM(_BSP_init)
!  nop
  mov %g0, %l6
  /* these are copied from above */
  ! Get bits (PHYSMEM_ADDR_SIZE - 1):13 of physmem_base.
  srlx %l6, 13, %l5

  ! l5 <= physmem_base[(PHYSMEM_ADDR_SIZE - 1):13]
  sllx %l5, 13 + (63 - (PHYSMEM_ADDR_SIZE - 1)), %l5
  srlx %l5, 63 - (PHYSMEM_ADDR_SIZE - 1), %l5

	wr %g0, ASI_DMMU, %asi

  set _start, %g5
  ! First 512K
  SET_TLB_TAG(0x4000, g1, MEM_CONTEXT_KERNEL)
  stxa %g1, [VA_DMMU_TAG_ACCESS] %asi     
  membar #Sync
  SET_TLB_DATA(g1, g2, TTE_W) ! use non-global mapping
  stxa %g1, [%g0] ASI_DTLB_DATA_IN_REG    
  membar #Sync

	SET_TLB_TAG(0x4000, g1, MEM_CONTEXT_KERNEL)
	mov VA_DMMU_TAG_ACCESS, %g2
	stxa %g1, [%g2] ASI_IMMU
	flush %g5
	SET_TLB_DATA(g1, g2, 0)		! use non-global mapping
	stxa %g1, [%g0] ASI_ITLB_DATA_IN_REG		
	flush %g5

!	call rtems_cache_flush_entire_data
!	nop

  /* precompute mapping for 512K pages */
  sethi %hi(sparc64_512K_tlb_data_template), %l4
  ldx [%l4 + %lo(sparc64_512K_tlb_data_template)], %l3
  or %l3, %l5, %l3
  stx %l3, [%l4 + %lo(sparc64_512K_tlb_data_template)]

  sethi %hi(real_trap_table), %o0
  rdpr  %tba, %o2
  stx   %o2, [%o0 + %lo(real_trap_table)]
	sethi %hi(trap_table), %g1
	wrpr %g1, %lo(trap_table), %tba



  setx sparc64_identity_map_dtlb, %l0, %o1
  setx param_space, %l0, %o2
  call SYM(_CPU_ISR_install_raw_handler)
  mov 0x68, %o0

  /* Clear the bss */
	setx	SYM(bss_start), %l0, %g2	! g2 = start of bss
	setx	SYM(_end), %l0, %g3		    ! g3 = end of bss
zerobss:
	stx	%g0, [%g2]
	add	%g2, 8, %g2
	cmp	%g2, %g3
	bleu,a	zerobss
	nop

  wrpr %g0, 1, %tl
	setx ofw_cif, %l0, %l1
 
	call ofw_init		! initialize OpenFirmware
	stx %o4, [%l1]
  wrpr %g0, 0, %tl


  call bootstrap
  nop


  /* Set up ISR handler for interrupt enable/disable */
	setx SYM(syscall), %l0, %o1
	setx param_space, %l0, %o2
	call SYM(_CPU_ISR_install_raw_handler)
	mov 0x100, %o0 

  /* Don't need to copy initialized data to RAM--link puts all in RAM already */

	mov	%g0, %o0		! clear command line passed to main
	call SYM(boot_card)
	sub	%sp, 0x60, %sp		! make room on stack (necessary?)

  call SYM(halt)
  nop

halted:	nop
	    b SYM(halted)

.section BOOTSTRAP
  .align CPU_ALIGNMENT
    .space 32768
    .global StackStart
    StackStart:
      .space 32768

.section BOOTSTRAP
  .align CPU_ALIGNMENT
    .global param_space
    param_space:
  	  .space 8

.section .fini
    .global _fini
    _fini:
    nop
    retl
    nop

.section .init
    .global _init
    _init:
    nop
    retl
    nop
